//⽅法装饰器
//基本语法
/*
 参数说明：
 ○ target: 对于静态⽅法来说值是类，对于实例⽅法来说值是原型对象。
 ○ propertyKey:⽅法的名称。
 ○ descriptor: ⽅法的描述对象，其中value属性是被装饰的⽅法。
*/

/*
 参数说明：
 ○ target: 对于静态⽅法来说值是类，对于实例⽅法来说值是原型对象。
 ○ propertyKey:⽅法的名称。
 ○ descriptor: ⽅法的描述对象，其中value属性是被装饰的⽅法。
*/
function Demo(target: object, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log(target)
    console.log(propertyKey)
    console.log(descriptor)
}

class Person22 {
    constructor(
        public name: string,
        public age: number,
    ) {

    }
    // Demo装饰实例⽅法
    @Demo
    speak() {
        console.log(`你好，我的名字：${this.name}，我的年龄：${this.age}`)
    }
    // Demo装饰静态⽅法
    @Demo
    static isAdult(age: number) {
        return age >= 18;
    }
}

//应⽤举例
// 需求：
//   1. 定义⼀个 Logger ⽅法装饰器，⽤于在⽅法执⾏前和执⾏后，均追加⼀些额外逻辑。
//   2. 定义⼀个 Validate ⽅法装饰器，⽤于验证数据。

function Logger(target: object, propertyKey: string, descriptor: PropertyDescriptor) {
    //存储原始方法
    const originnal = descriptor.value
    // 替换原始⽅法
    descriptor.value = function (...args: any[]) {
        console.log(`${propertyKey}开始执⾏......`)
        const result = originnal.call(this, ...args)
        console.log(`${propertyKey}执⾏完毕......`)
        return result
    }
}

//装饰器工厂
function Validate(maxValue: number) {
    return function (target: object, propertyKey: string, descriptor: PropertyDescriptor) {
        // 保存原始⽅法
        const original = descriptor.value;
        // 替换原始⽅法
        descriptor.value = function (...args: any[]) {
            // ⾃定义的验证逻辑
            if (args[0] > maxValue) {
                throw new Error('年龄⾮法！')
            }
            // 如果所有参数都符合要求，则调⽤原始⽅法
            return original.apply(this, args);
        };
    }
}

class Person23 {
    constructor(
        public name: string,
        public age: number,
    ) { }
    //AOP
    @Logger
    speak(str: string) {
        console.log(`你好，我的名字：${this.name}，我的年龄：${this.age}，----${str}`)
    }
    @Validate(18)
    static isAdult(age: number) {
        return age >= 18;
    }
}

const p23 = new Person23("漳卅", 18)
p23.speak("xxxxxxxxxxxxxx")
console.log(Person23.isAdult(19))

